feat(cron): add publish-due endpoint and rebuildHooks config#772
feat(cron): add publish-due endpoint and rebuildHooks config#772michaelmcker wants to merge 2 commits into
Conversation
Adds POST /_emdash/api/cron/publish-due to publish all content items whose scheduled_at has passed, then fire content:afterPublish hooks per item and rebuild hooks once for the batch. - New route secured by EMDASH_CRON_SECRET (or CRON_SECRET for Vercel) - Constant-time token comparison via SHA-256 XOR - rebuildHooks?: string[] config option fires POST to each URL after batch via after() so Workers doesn't cancel in-flight fetches - Per-item publish failures are logged and skipped (batch continues) - handleContentPublishDue exported from core package - Integrates into runSystemCleanup via optional publishFn callback - 6 unit tests covering all required scenarios Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…SH_CRON_SECRET - New guide: guides/scheduled-publishing.mdx — covers setup steps for Vercel Cron, Cloudflare Workers scheduled events, and self-hosted cron, plus how to get deploy hook URLs from Vercel/Netlify/CF Pages - configuration.mdx: document rebuildHooks option with example and fire-and-forget semantics note - configuration.mdx: add EMDASH_CRON_SECRET to env vars table with CRON_SECRET fallback note for Vercel Cron compatibility - Sidebar: add Scheduled Publishing entry in Guides Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Scope checkThis PR changes 628 lines across 15 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
🦋 Changeset detectedLatest commit: 24691af The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
|
This PR has been inactive for 14 days. It will be closed automatically in 7 days if there is no further activity. If you're still working on this, please push an update or leave a comment. |
There was a problem hiding this comment.
The approach is sound: a cron-facing HTTP endpoint for scheduled publishing plus configurable rebuild hooks fits EmDash's architecture well. The implementation is mostly clean, but the endpoint is non-functional as-is because the auth middleware blocks it before the route handler can validate the cron secret. I also found docs referencing non-existent code and a docs/code mismatch on when rebuild hooks fire.
Headline issues
- Cron endpoint is unreachable —
auth.tsrejects theAuthorization: Bearer <cron_secret>header (it expectsec_pat_/ec_oat_tokens) and enforcesX-EmDash-RequestCSRF on non-public API routes, so the route handler’s secret check never runs. The route needs to be added toPUBLIC_API_PREFIXES. - Docs reference missing
handleScheduledhelper — the Cloudflare Workers docs tell users to importhandleScheduledfromemdash/astro/scheduled, which does not exist. - Rebuild hooks don't fire on unpublish — the updated docs say hooks run after "published or unpublished", but
handleContentUnpublishnever callsfireRebuildHooks(). - Dead code in cleanup.ts —
runSystemCleanupaccepts apublishFnparameter andpublishDueContentwas added, but the only caller inemdash-runtime.tsnever passes it, so that code path is never exercised.
Process note: This PR adds a user-facing feature but the PR template’s "approved Discussion" checkbox is unchecked. AGENTS.md requires one for features.
What I checked: auth middleware flow, API route conventions (envelope shape, CSRF, error handling), hook firing paths, cleanup scheduler wiring, SQL safety (sql.ref usage is correct), index coverage (scheduled_at partial index exists), docs accuracy, and test coverage (6 unit tests).
What does this PR do?
Adds a
POST /_emdash/api/cron/publish-dueendpoint that publishes all content items whosescheduled_athas passed and fires configuredrebuildHooksonce per batch.Also adds the
rebuildHooksoption to the integration config so users can point EmDash at a Vercel / Netlify / Cloudflare deploy hook URL to trigger a rebuild whenever scheduled content goes live.Closes #
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runpnpm locale:extracthas been run (if applicable)AI-generated code disclosure
What's included
POST /_emdash/api/cron/publish-duescheduled_at <= nowandstatus = 'scheduled'content:afterPublishhooks per itemrebuildHooksonce for the whole batch (not per item)Authorization: Bearer <EMDASH_CRON_SECRET>when the env var is set; localhost-only in dev; 503 if neither appliesrebuildHooksconfig optionEach URL receives a
POSTrequest after a publish batch. Requests are deferred past the response viaafter()so the isolate response isn't blocked. Failures are logged but never surfaced as errors.Tests — 6 unit tests in
tests/unit/api/publish-due.test.tscovering: empty (no-op), past-scheduled item published, future item skipped, multiple items across collections, idempotency (second call publishes 0), and items returned for hook dispatch.Docs — new
guides/scheduled-publishing.mdxand updatedreference/configuration.mdx.Screenshots / test output